const bcrypt = require("bcryptjs");
const { Op, where } = require("sequelize");
const {
  User,
  Role,
  sequelize,
  Menu,
  MenuButton,
  UserRole,
  RoleMenu,
} = require("../../../../models");
const utils = require("../../../../utils");
const userRoleService = require("../../user_role");
module.exports = {
  // 创建/编辑用户
  async saveOrUpdateUser(req, res, next) {
    try {
      const { id, roleIds } = req.body;
      // 校验角色数据是否正常
      await userRoleService.checkRoleIds(roleIds);
      // 保存或更新用户数据
      return id
        ? this.updateUser(req, res, next)
        : this.saveUser(req, res, next);
    } catch (error) {
      next(error);
    }
  },

  // 创建用户
  async saveUser(req, res, next) {
    try {
      // 事务托管
      await sequelize.transaction(async (t) => {
        // 创建用户时，对密码进行加密
        const params = {
          ...req.body,
          password: bcrypt.hashSync(req.body.password, 12), // 加密密码
        };
        const user = await User.create(params, { transaction: t });
        if (!user) {
          throw new Error("创建用户失败");
        }
        // 更新用户角色关联表信息
        await userRoleService.updateUserRoleByUserId(
          {
            userId: user.dataValues.id,
            roleIds: req.body.roleIds,
          },
          t
        );
        // 更新失败 删除用户
        res.cc(null, "成功创建用户");
      });
    } catch (error) {
      next(error);
    }
  },

  // 更新用户
  async updateUser(req, res, next) {
    try {
      if (req.body.id === "1") {
        throw new Error("超级管理员不允许修改");
      }
      // 事务托管
      await sequelize.transaction(async (t) => {
        // 1、校验用户是否存在
        let userItem = await this.checkUserById(req, res, next);
        if (!userItem) return;
        // 2、组装参数
        await utils.assignEditValue(userItem, req.body, ["password"]);
        // 3、执行更新
        const result = await userItem.save({ transaction: t });
        if (result) {
          // 更新用户角色关联表信息
          await userRoleService.updateUserRoleByUserId(
            {
              userId: result.dataValues.id,
              roleIds: req.body.roleIds,
            },
            t
          );
        }
        res.cc(null, "更新成功");
      });
    } catch (error) {
      next(error);
    }
  },

  // 获取当前登录用户信息
  async getUserInfoByAuth(req, res, next) {
    try {
      const user = await this.getUserInfoById(req.auth.id);
      res.cc(user, "成功获取用户信息");
    } catch (error) {
      next(error);
    }
  },

  // 通过id获取用户信息
  async getUserInfo(req, res, next) {
    try {
      const user = await this.getUserInfoById(req.body.id);
      res.cc(user, "成功获取用户信息");
    } catch (error) {
      next(error);
    }
  },

  // 通过id获取当前登录的用户信息
  async getUserInfoById(id) {
    if (!id) {
      throw new Error("id不能为空");
    }
    const user = await User.findOne({
      where: { id },
      include: [
        {
          model: Role,
          attributes: ["id", "roleName"],
          as: "roles",
          through: { attributes: [] },
        },
      ],
    });
    if (!user) {
      throw new Error("用户不存在");
    }
    delete user.dataValues.password;

    return user;
  },
  getBtnPerms(menuList, params = "all") {
    const btnPerms = {};
    menuList.forEach((menuItem) => {
      if (menuItem.buttons.length > 0) {
        // 全量数据时全部读取
        if (params === "all") {
          btnPerms[menuItem.routeName] = menuItem.buttons.map((el) => el.perms);
        } else {
          // 否则按需读取
          for (const menuId of Object.keys(params)) {
            if (menuItem.id === menuId) {
              btnPerms[menuItem.routeName] = menuItem.buttons
                .filter((el) => params[menuId].includes(el.id))
                .map((el) => el.perms);
            }
          }
        }
      }
    });
    return btnPerms;
  },

  // 获取当前用户的菜单、按钮数据
  async getUserMenuAuth(req, res, next) {
    try {
      const menuList = await Menu.findAll({
        order: [["sort", "ASC"]],
        include: {
          model: MenuButton,
          as: "buttons",
          where: {
            isUse: 1,
          },
          attributes: ["id", "perms"],
          required: false,
        },
      });
      const plainMenuList = menuList.map((item) => item.get({ plain: true }));
      // 超管返回全量数据
      if (req.auth.id === "1") {
        const btnPerms = await this.getBtnPerms(plainMenuList);
        const adminMenuData = await utils.arrToTree(plainMenuList ?? []);
        return res.cc(
          {
            menu: adminMenuData,
            btnPerms,
          },
          "成功获取超管菜单权限"
        );
      }

      // 使用关联表查询当前用户所有的角色
      const userRoleList = await UserRole.findAll({
        raw: true,
        where: {
          userId: req.auth.id,
        },
      });
      const roleIds = userRoleList.map((item) => item.roleId);
      // 使用关联表查询角色的权限
      const roleMenus = await RoleMenu.findAll({
        raw: true,
        where: {
          roleId: {
            [Op.in]: roleIds,
          },
        },
      });

      const params = {},
        menuIds = [];
      roleMenus.forEach((item) => {
        menuIds.push(item.menuId);
        if (item.btnIds) {
          params[item.menuId] = item.btnIds.split(",");
        }
      });
      const btnPerms = await this.getBtnPerms(plainMenuList, params);
      const result = utils.getAllParentsByIds(menuIds, plainMenuList);

      const data = await utils.arrToTree(result ?? []);
      res.cc({
        menu: data,
        btnPerms,
      });
    } catch (error) {
      next(error);
    }
  },

  // 校验用户是否存在 如果存在 返回用户信息
  async checkUserById(req, res, next) {
    try {
      const { id } = req.body;
      if (!id) {
        throw new Error("id不能为空");
      }
      // if (id === "1") {
      //   return res.err("超级管理员不能修改/删除");
      // }
      const user = await User.findByPk(id);
      if (!user) {
        throw new Error("用户不存在");
      }
      return user;
    } catch (error) {
      next(error);
    }
  },

  // 根据账号校验用户是否存在 account唯一
  async checkUserByAccount(req, res, next) {
    try {
      const { account } = req.body;
      if (!account) {
        return res.err("请输入账号");
      }
      const user = await User.findOne({
        where: { account },
        include: [
          {
            model: Role,
            attributes: ["id", "roleName"],
            through: { attributes: [] },
            as: "roles",
          },
        ],
      });
      if (!user) {
        return res.err("账号不存在");
      }
      return user;
    } catch (error) {
      next(error);
    }
  },

  // 根据手机号校验用户是否存在 phone唯一
  async checkUserByMobile(req, res, next) {
    try {
      const { mobile } = req.body;
      if (!mobile) {
        return res.err("未传递手机号信息");
      }
      const user = await User.findOne({ where: { mobile } });
      if (!user) {
        return res.err("用户不存在");
      }
      return user;
    } catch (error) {
      next(error);
    }
  },

  // 校验密码是否正确
  async comparePassword(formPassword, sqlPassword) {
    const isMatch = await bcrypt.compare(formPassword, sqlPassword);
    if (!isMatch) {
      throw new Error("密码错误,请检查后重试");
    }
    return isMatch;
  },

  // 根据id删除用户
  async deleteUserById(req, res, next) {
    try {
      if (req.body.id === "1") {
        throw new Error("超级管理员不能删除");
      }
      await this.checkUserById(req, res, next);
      const result = await User.destroy({ where: { id: req.body.id } });
      return result ? res.cc(null, "删除成功") : res.err("删除失败");
    } catch (error) {
      next(error);
    }
  },

  // 查询全量接口
  async getUserList(req, res, next) {
    try {
      const params = await this.getSearchParams(req);
      const users = await User.findAll(params);
      return res.cc(users, "查询成功");
    } catch (error) {
      next(error);
    }
  },

  // 分页查询接口
  async getUserPage(req, res, next) {
    try {
      const params = await this.getSearchParams(req, "page");
      const { count, rows } = await User.findAndCountAll({
        ...params,
        distinct: true,
      });
      return res.page(count, rows);
    } catch (error) {
      next(error);
    }
  },

  // 修改密码
  async changePassword(req, res, next) {
    try {
      req.body.id = req.auth.id;
      const userItem = await this.checkUserById(req, res, next);
      if (!userItem) return;
      await this.comparePassword(
        req.body.password,
        userItem.dataValues.password
      );
      userItem.password = bcrypt.hashSync(req.body.newPassword, 12); // 加密密码
      const result = await userItem.save();
      return result ? res.cc(null, "已成功修改密码") : res.err("修改密码失败");
    } catch (error) {
      next(error);
    }
  },

  // 重置密码
  async resetPassword(req, res, next) {
    try {
      if (req.auth.id !== "1") {
        return res.err("无权限操作");
      }
      const userItem = await this.checkUserById(req, res, next);
      if (!userItem) return;
      userItem.password = bcrypt.hashSync("123456", 12); // 加密密码
      const result = await userItem.save();
      return result
        ? res.cc(null, "已成功重置密码,重置默认密码为:123456")
        : res.err("重置密码失败");
    } catch (error) {
      next(error);
    }
  },

  // 组装查询参数
  async getSearchParams(req, type = "list") {
    const { userName, mobile, gender, page = 1, limit = 12 } = req.body;
    const pageParams = {
      limit: parseInt(limit),
      offset: (parseInt(page) - 1) * parseInt(limit),
    };
    return {
      order: [
        // [
        //   sequelize.literal("CASE WHEN `User`.`id` = 1 THEN 0 ELSE 1 END"),
        //   "ASC",
        // ], // 将超管排在最前面
        ["createTime", "ASC"],
      ],
      attributes: { exclude: ["password"] },
      ...(type === "page" ? pageParams : {}), // 查询全量数据时，不进行分页
      where: {
        userName: {
          [Op.like]: `%${userName ?? ""}%`,
        },
        mobile: {
          [Op.like]: `%${mobile ?? ""}%`,
        },
        ...(gender ? { gender } : {}), // gender存在时，才添加查询条件
        ...(req.auth.id !== "1" // 只有超管才能看到这条数据
          ? {
              id: {
                [Op.ne]: "1",
              },
            }
          : {}),
      },
      include: [
        {
          model: Role,
          attributes: ["id", "roleName"],
          as: "roles",
          through: { attributes: [] },
        },
      ],
    };
  },
};
